package light.network;

import java.nio.ByteBuffer;

/**
 * Tcp数据包
 * 
 * @author tanjiazhang 创建方式 Pack.allocate(capacity)
 *         格式：HeaderFlag-PacketLength-ByteData
 */
public class TcpPacket implements Packet {

	public static final int MaxLength = 32 * 1024;
	public static final int HeaderFlag = 0;
	private static final int Offset = 8;
	ByteBuffer data;

	public static Packet allocate(int capacity) {
		return new TcpPacket(capacity);
	}

	public static TcpPacket wrap(ByteBuffer src) {
		return new TcpPacket(src);
	}

	public static int validateLength(ByteBuffer buf) {
		if (buf.getInt(buf.position()) != HeaderFlag)
			return -1;
		int len = buf.getInt(buf.position() + 4);
		if (len < 0 || len > MaxLength)
			return -1;
		else
			return len;
	}

	private TcpPacket(int capacity) {
		data = ByteBuffer.allocate(capacity);
	}

	private TcpPacket(ByteBuffer src) {
		data = ByteBuffer.wrap(src.array(), src.position() + Offset, src.limit() - src.position() - Offset);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see light.network.IPacket#getLength()
	 */
	@Override
	public int getLength() {
		return data.limit() - data.position();
	}

	public ByteBuffer[] genPacketBuffer() {
		ByteBuffer[] buf = new ByteBuffer[2];
		ByteBuffer f = (ByteBuffer) ByteBuffer.allocate(8).putInt(HeaderFlag).putInt(getLength() + Offset).flip();
		buf[0] = f;
		buf[1] = data;
		return buf;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see light.network.IPacket#validate()
	 */
	@Override
	public boolean validate() {
		if (HeaderFlag != data.getInt(0))
			return false;
		int len = getLength();
		if (len > MaxLength)
			return false;
		if (len == (limit() - position()))
			return true;
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see light.network.IPacket#buffer()
	 */
	@Override
	public ByteBuffer buffer() {
		return data;
	}

	public final int capacity() {
		return data.capacity();
	}

	public final int position() {
		return data.position();
	}

	public final Packet position(int newPosition) {
		data.position(newPosition);
		return this;
	}

	public final int limit() {
		return data.limit();
	}

	public final Packet limit(int newLimit) {
		data.limit(newLimit);
		return this;
	}

	public final Packet clear() {
		data.clear();
		return this;
	}

	public byte get() {
		return data.get();
	}

	public Packet put(byte b) {
		data.put(b);
		return this;
	}

	public byte get(int index) {
		return data.get(index);
	}

	public Packet put(int index, byte b) {
		data.put(index, b);
		return this;
	}

	public Packet put(ByteBuffer src) {
		data.put(src);
		return this;
	}

	public Packet put(byte[] src, int offset, int length) {
		data.put(src, offset, length);
		return this;
	}

	public final Packet put(byte[] src) {
		data.put(src);
		return this;
	}

	public char getChar() {
		return data.getChar();
	}

	public Packet putChar(char value) {
		data.putChar(value);
		return this;
	}

	public char getChar(int index) {
		return data.getChar(index);
	}

	public Packet putChar(int index, char value) {
		data.putChar(index, value);
		return this;
	}

	public short getShort() {
		return data.getShort();
	}

	public Packet putShort(short value) {
		data.putShort(value);
		return this;
	}

	public short getShort(int index) {
		return data.getShort(index);
	}

	public Packet putShort(int index, short value) {
		data.putShort(index, value);
		return this;
	}

	public int getInt() {
		return data.getInt();
	}

	public Packet putInt(int value) {
		data.putInt(value);
		return this;
	}

	public int getInt(int index) {
		return data.getInt(index);
	}

	public Packet putInt(int index, int value) {
		data.putInt(index, value);
		return this;
	}

	public long getLong() {
		return data.getLong();
	}

	public Packet putLong(long value) {
		data.putLong(value);
		return this;
	}

	public long getLong(int index) {
		return data.getLong(index);
	}

	public Packet putLong(int index, long value) {
		data.putLong(index, value);
		return this;
	}

	public float getFloat() {
		return data.getFloat();
	}

	public Packet putFloat(float value) {
		data.putFloat(value);
		return this;
	}

	public float getFloat(int index) {
		return data.getFloat(index);
	}

	public Packet putFloat(int index, float value) {
		data.putFloat(index, value);
		return this;
	}

	public double getDouble() {
		return data.getDouble();
	}

	public Packet putDouble(double value) {
		data.putDouble(value);
		return this;
	}

	public double getDouble(int index) {
		return data.getDouble(index);
	}

	public Packet putDouble(int index, double value) {
		data.putDouble(index, value);
		return this;
	}

	@Override
	public byte[] array() {
		return data.array();
	}

	@Override
	public Packet flip() {
		data.flip();
		return this;
	}

	@Override
	public ByteData data() {
		return new ByteData(data.array(), 0, getLength());
	}
}
